﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>




！！！文件打开和关闭
以只读的形式打开文本文件（data。xtx）
int main()
{
	FILE* pf = fopen("data.txt", "r");
 fclose(pf);
 pf = NULL;
	return 0;
}



以只读的形式打开文本文档（text.txt），因为不存在所以会报错
int main()
{
	FILE* pd = fopen("text.txt", "r");
	if (pd == NULL)
	{
		perror("foprn");
		return 1;
	}
 fclose(pf);
 pf = NULL;
	return 0;
}


以只写的形式打开文本文件（data。txt），成功打开并清空文件内容
int main()
{
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
 fclose(pf);
 pf = NULL;
	return 0;
}




以只写的形式打开文本文件（test。txt）因为文件不存在，所以会创建一个新的文件命名为test。txt
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
 fclose(pf);
 pf = NULL;
	return 0;
}









文件读写

//！！！fgetc(读字符)！！！
int main()
{
 //打开文件
	FILE* pf = fopen("data.txt", "r");
	if(pf == NULL)
	{
		perror("fopen");
		return 1;
	}
 //进行读操作
	int ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	return 0;
}



//！！！foutc(写字符）！！！
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//进行写操作
	fputc('a', pf);
	fputc('b', pf);
	fputc('c', pf);
	fputc('d', pf);
	fputc('e', pf);
	fputc('f', pf);
	fputc('g', pf);
	//写入abcdefg，它会把之前的文件清空再写入
	return 0;
}



写入26字母
int main()
{
	//以只写的形式打开文件
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写入26个字母
	int i = 0;
	for (i = 'a'; i <='z'; i++)
	{
		fputc(i, pf);
	}
  fclose(pf);
  pf = NULL;
	return 0;
}

读26个字母
int main()
{
	//以只写的形式打开文件
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读入26个字母
	int i = 0;
	for (i = 0; i < 26; i++)
	{
		printf("%c ", fgetc(pf));
	}
  fclose(pf);
  pf = NULL;
	return 0;
}



写入26个字母并读在屏幕上
int main()
{
	//以只写的形式打开文件
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写入26个字母
	int i = 0;
	for (i = 'a'; i <='z'; i++)
	{
		fputc(i, pf);
	}
	fclose(pf);
	pf = NULL;
	FILE* pd = fopen("data.txt", "r");
	if (pd == NULL)
	{
		perror("fopen");
		return 2;
	}
	int j = 0;
	for (j = 0; j < 26; j++)
	{
		printf("%c ", fgetc(pd));
	}
	fclose(pd);
	pd = NULL;

	return 0;
}



文本行的输入输出！！！


fputs:文本行输出函数（写文本）

int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("Fopen");
		return 1;
	}
	//写函数
	fputs("i am you father\n", pf);
	fputs("no you are my son\n", pf);
  //关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}




fgets:文本行输入函数（读文件）

int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	char arr[20] = { "xxxxxxxxxxxxxx" };
	fgets(arr, 5, pf);
	printf("%s\n", arr);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}




基本输入输出流
int main()
{
	char arr[20] = { 0 };
	fgets(arr,20, stdin);
	fputs(arr, stdout);
	return 0;
}
 





fprintf：格式化输出函数
struct s
{
	char name[20];
	int year;
	float num;
};

int main()
{
	struct s s1 = { "hzl",18,90.5f };
	//打开文件
	FILE* pf = fopen("data.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写带格式的数据到文件
	fprintf(pf, "%s %d %.1f", s1.name, s1.year, s1.num);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}





fscanf:格式化输入函数
struct s
{
	char name[20];
	int year;
	float num;
};

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	struct s s1;
	fscanf(pf, "%s %d %f", s1.name, &(s1.year), &(s1.num));
	printf("%s %d %.1f", s1.name, s1.year, s1.num);
	fclose(pf);
	pf = NULL;
	return 0;
}





//补充：sprintf,sscanf
//sprintf:将格式化的数据转换成字符串
//sscanf：将字符串转换成格式化的数据
struct s
{
	char name[20];
	int year;
	float num;
};

int main()
{
	struct s s1 = { "dg",28,88.8f };
	//给一个存放数据的字符串数组
	char arr[100];
	//将结构体数据s1转换成字符串
	sprintf(arr, "%s %d %.1f\n", s1.name, s1.year, s1.num);
	printf("%s", arr);
	struct s s2;
	//将字符串数据转换成结构体数据s2
	sscanf(arr, "%s %d %f", s2.name, &(s2.year), &(s2.num));
	printf("%s %d %.1f", s2.name, s2.year, s2.num);
	return 0;
}




fwrite:二进制输出
将数据以二进制的形式输出到文件
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
size_t:表示写入多少元素就返回多少个数（比如写入三个元素就返回3）
ptr:表示指向一段数据的地址，从这个地址的数据里拿出数据写入文件
size和count:表示写入count个大小为size的数据
stream:表示被写入的文件
struct s
{
	char name[20];
	int age;
	float num;
};

int main()
{
	struct s s1 = { "翠花",20,90.5f };
	//以二进制写入的形式打开文件
	FILE* pf = fopen("data.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	size_t i = fwrite(&s1, sizeof(struct s), 1, pf);
  printf("%zd",i);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}




fread:二进制输入
size_t fwrite ( void * ptr, size_t size, size_t count, FILE * stream );
size_t:表示读取多少元素就返回多少个数（比如读取三个元素就返回3）
ptr:表示指向一段数据的地址，把文件里的数据读取到这个地址上
size和count:表示读取count个大小为size的数据
stream:表示被读取的文件
表示从文件中读取count个大小为size的元素到ptr指向的地址空间上。
是读二进制形式存放的文件，给它正常读取出来
struct s
{
	char name[20];
	int age;
	float num;
};

int main()
{
	//刚刚上面已经在data.txt文件中写了一串二进制的数据，现在读取他

	//创建一个地址空海军存放读取的数据
	struct s s2;

	//打开文件
	FILE* pf = fopen("data.txt", " rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	size_t i = fread(&s2, sizeof(struct s), 1, pf);
	printf("%s %d %.1f\n", s2.name, s2.age, s2.num);
	printf("%zd", i);
	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}




文件的随机读写


fSeek：根据⽂件指针的位置和偏移量来定位（⽂件内容的！光标！）文件指针
int fseek ( FILE * stream, long int offset, int origin );
返回值：如果成功，返回0，否则返回非0的值
offset：表示偏移量
origin：表示光标起始位置，有三种：1.SEEK_SET(文件开头）2.SEEK_CUP(光标当前位置）3.SEEK_END(文件末尾）
stream：文件指针

int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	if (!pf)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	int ch;
	ch  = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	//想直接打印e
	//把光标定位到e
	//fseek(pf, 4, SEEK_SET);
	//fseek(pf, 2, SEEK_CUR);
	fseek(pf, -2, SEEK_END);
	ch = fgetc(pf);
	printf("%c\n", ch);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}




ftell:返回⽂件指针（光标）相对于起始位置的偏移量
long int ftell ( FILE * stream );

int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	if (!pf)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	int ch;
	ch  = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	//想直接打印e
	//把光标定位到e
	//fseek(pf, 4, SEEK_SET);
	//fseek(pf, 2, SEEK_CUR);
	fseek(pf, -2, SEEK_END);
	ch = fgetc(pf);
	printf("%c\n", ch);
	long int i = ftell(pf);
	printf("%d", i);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}




rewind：让⽂件指针（光标）的位置回到⽂件的起始位置
void rewind ( FILE * stream );

int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	if (!pf)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	int ch;
	ch  = fgetc(pf);
	ch  = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	//想直接打印e
	//把光标定位到e
	//fseek(pf, 4, SEEK_SET);
	//fseek(pf, 2, SEEK_CUR);
	fseek(pf, -2, SEEK_END);
	ch = fgetc(pf);
	printf("%c\n", ch);
	//把文件指针（光标）返回文件起始位置
	rewind(pf);
	ch = fgetc(pf);
	printf("%c", ch);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}


7. ⽂件读取结束的判定
7.1 被错误使⽤的 feofQAQ1
牢记：在⽂件读取过程中，不能⽤feof函数的返回值直接来判断⽂件的是否结束。

feof 的作⽤是：当⽂件！读取！结束的时候，判断读取结束的原因是否是：遇到⽂件尾结束。
如果是遇到文件结尾：返回非0值，不是则放回0.

ferror 的作用是：判断文件是否成功读/写，如果失败了则返回非0值，成功读/写返回0

1. ⽂本⽂件读取是否结束，判断返回值是否为 EOF （ fgetc ），或者 NULL （ fgets ）
例如：
• fgetc 判断是否为 EOF .
• fgets 判断返回值是否为 NULL .
2. ⼆进制⽂件的读取结束判断，判断返回值是否⼩于实际要读的个数。
例如：
• fread判断返回值是否⼩于实际要读的个数。


拷贝文件
把data1.txt的文件拷贝到data2.txt
int main()
{
	//只读的形式打开data1。txt文件
	FILE* pfread = fopen("data1.txt", "r");
	if (pfread == NULL)
	{
		perror("fopen\n");
		return 1;
	}
	//只写的形式打开data2.txt
	FILE* pfwrite = fopen("data2.txt","w");
	if (pfwrite == NULL)
	{
		perror("fopen\n");
		fclose(pfread);
		return 1;
	}
	//拷贝
	int ch = 0;
	while ((ch = fgetc(pfread)) != EOF)
	{
		
		fputc(ch, pfwrite);
	}
	fclose(pfread);
	pfread = NULL;
	fclose(pfwrite);
	pfwrite = NULL;
	return 0;
}